package data.selection;

import java.awt.Color;
import java.util.List;

import data.Data;
import data.Position;
import data.Data.Zones;
import engine.Pitch;

/**
 * Class that acts as a filter to show selection, what is possible and what is not.
 * Also returns a color so that it can be easier to see visually in the game.
 * @author Julien
 *
 */
public class SelectionObject {
	private SelectionMethod m_selectionMethod;
	private Color m_color;
	private boolean m_invert;
	
	/**
	 * Clean constructor that will be called by subclasses
	 */
	protected SelectionObject()
	{
		m_selectionMethod = null;
		m_invert          = false;
		m_color           = null;
	}
	
	/**
	 * Constructs the selection object for a custom operation, using the parameters.
	 * @param method The selection method that tells if a position is selected or not.
	 * @param invert True if we need to invert the results.
	 * @param color The color to color the selected cells.
	 */
	public SelectionObject( SelectionMethod method, boolean invert, Color color )
	{
		m_selectionMethod = method;
		m_invert          = invert;
		m_color           = color;
	}
	
	/**
	 * Constructs the selection object for a custom operation, using the parameters.
	 * The color used is the default color (some transparent black)
	 * @param method The selection method that tells if a position is selected or not.
	 * @param invert True if we need to invert the results.
	 */
	public SelectionObject( SelectionMethod method, boolean invert )
	{
		this( method, invert, m_defaultColor );
	}
	
	/**
	 * Constructs the selection object for a custom operation, using the parameters.
	 * The color used is the default color (some transparent black)
	 * The selection will not be inverted.
	 * @param method The selection method that tells if a position is selected or not.
	 */
	public SelectionObject( SelectionMethod method )
	{
		this( method, false, m_defaultColor );
	}
	
	/**
	 * Constructs the selection object for a standard pitch zone, using the parameters.
	 * @param zone The zone that will be selected.
	 * @param invert True if we want to invert the selection.
	 * @param color Color of the highlight.
	 */
	public SelectionObject( Zones zone, boolean invert, Color color )
	{
		m_selectionMethod = new StandardSelectionMethod( zone );
		m_invert = invert;
		m_color = color;
	}
	
	/**
	 * Constructs the selection object for a standard pitch zone, using the parameters.
	 * The color used is the default color (some transparent black).
	 * @param zone The zone that will be selected.
	 * @param invert True if we want to invert the selection.
	 */
	public SelectionObject( Zones zone, boolean invert )
	{
		this( zone, invert, m_defaultColor );
	}
	
	/**
	 * Constructs the selection object for a standard pitch zone, using the parameters.
	 * The color used is the default color (some transparent black).
	 * The selection will not be inverted.
	 * @param zone The zone that will be selected.
	 */
	public SelectionObject( Zones zone )
	{
		this( zone, false, m_defaultColor );
	}
	
	/**
	 * Constructs the selection object using the position list given, and the parameters.
	 * @param pos A list of the position to be selected.
	 * @param invert True if we want to invert the selection.
	 * @param color Color of the highlight.
	 */
	public SelectionObject( List<Position> pos, boolean invert, Color color )
	{
		m_selectionMethod = new PositionListSelectionMethod( pos );
		m_invert = invert;
		m_color = color;
	}

	/**
	 * Constructs the selection object using the position list given, and the parameters.
	 * The color used is the default color (some transparent black).
	 * @param pos A list of the position to be selected.
	 * @param invert True if we want to invert the selection.
	 */
	public SelectionObject( List<Position> pos, boolean invert )
	{
		this( pos, invert, m_defaultColor );
	}
	
	/**
	 * Constructs the selection object using the position list given, and the parameters.
	 * The color used is the default color (some transparent black).
	 * The selection will not be inverted.
	 * @param pos A list of the position to be selected.
	 */
	public SelectionObject( List<Position> pos )
	{
		this( pos, false, m_defaultColor );
	}
	
	/**
	 * Checks if the position is selected by this highlight
	 * @param pos the position to test.
	 * @return true if selected, false otherwise.
	 */
	public boolean isSelected( Position pos ) 
	{ 
		return m_invert ? !m_selectionMethod.isSelected(pos) : m_selectionMethod.isSelected(pos); 
	}
	
	/**
	 * Gives the color of the position, null if the position is not selected
	 * @param pos the target position
	 * @return The color this highlight gives, null if not selected
	 */
	public Color color(Position pos) 
	{
		if( isSelected(pos) )
			return m_color; 
		else 
			return null;
	}

	protected static Color m_defaultColor = new Color(0, 0, 0, 0.7f);
}

/**
 * Standard interface for selection methods, used with the Selection objects.
 * @author Julien
 *
 */
interface SelectionMethod {
	/**
	 * Checks if the position is "selected"
	 * @param pos the target position
	 * @return True if the position is selected, false otherwise.
	 */
	public boolean isSelected( Position pos );
}

/**
 * Standard selection class, using standard zones.
 * @author Julien
 *
 */
class StandardSelectionMethod implements SelectionMethod {
	Zones m_zone;
	
	public StandardSelectionMethod( Zones zone ) { m_zone = zone; }
		
	/**
	 * Checks if the position is "selected"
	 * @param pos the target position
	 * @return True if the position is selected, false otherwise.
	 */
	public boolean isSelected(Position pos)
	{
		switch( m_zone )
		{
		case LEFT_PITCH:      return Pitch.isZoneTeamA(pos); 
		case RIGHT_PITCH:     return Pitch.isZoneTeamB(pos);
		case TOP_WIDE:        return Pitch.isTopWideZone(pos);
		case BOTTOM_WIDE:     return Pitch.isBottomWideZone(pos);
		case LEFT_ENDZONE:    return Pitch.isEndZoneA(pos);
		case RIGHT_ENDZONE:   return Pitch.isEndZoneB(pos);
		case SCRIMMAGE_LINE:  return Pitch.isScrimmageZone(pos);
		case LEFT_SCRIMMAGE:  return Pitch.isScrimmageZoneTeamA(pos);
		case RIGHT_SCRIMMAGE: return Pitch.isScrimmageZoneTeamB(pos);
		}

		return false;
	}
}

/**
 * Standard class for position lists, implements the SelectionMethod interface
 * @author Julien
 *
 */
class PositionListSelectionMethod implements SelectionMethod {
	List<Position> m_positions;
	
	/**
	 * Constructs the selection method from a position list.
	 * @param pos The position list.
	 */
	public PositionListSelectionMethod( List<Position> pos )
	{
		m_positions = pos;
	}
	
	/**
	 * Checks if the position is "selected"
	 * @param pos the target position
	 * @return True if the position is selected, false otherwise.
	 */
	public boolean isSelected(Position pos)
	{
		for( Position position : m_positions )
			if( position.x() == pos.x() && position.y() == pos.y() )
				return true;
		
		return false;
	}
}